Passed
Branch wavefile-rw (3e4b6e)
by Rafael S.
02:30
created

WaveFileReader.readDs64Chunk_   A

Complexity

Conditions 3

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 26
rs 9.6
c 0
b 0
f 0
cc 3
1
/*
2
 * Copyright (c) 2017-2019 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview The WaveFileReader class.
27
 * @see https://github.com/rochars/wavefile
28
 */
29
30
import RIFFFile from './riff-file';
31
import writeString from './write-string';
32
import validateNumChannels from './validate-num-channels'; 
33
import validateSampleRate from './validate-sample-rate';
34
import {unpack} from 'byte-data';
35
36
/**
37
 * A class to read wav files.
38
 */
39
export default class WaveFileReader extends RIFFFile {
40
41
  /**
42
   * @param {?Uint8Array=} wavBuffer A wave file buffer.
43
   * @throws {Error} If container is not RIFF, RIFX or RF64.
44
   * @throws {Error} If format is not WAVE.
45
   * @throws {Error} If no 'fmt ' chunk is found.
46
   * @throws {Error} If no 'data' chunk is found.
47
   */
48
  constructor(wavBuffer=null) {
49
    super();
50
    /**
51
     * Audio formats.
52
     * Formats not listed here should be set to 65534,
53
     * the code for WAVE_FORMAT_EXTENSIBLE
54
     * @enum {number}
55
     * @protected
56
     */
57
    this.WAV_AUDIO_FORMATS = {
58
      '4': 17,
59
      '8': 1,
60
      '8a': 6,
61
      '8m': 7,
62
      '16': 1,
63
      '24': 1,
64
      '32': 1,
65
      '32f': 3,
66
      '64': 3
67
    };
68
    /**
69
     * The data of the 'fmt' chunk.
70
     * @type {!Object<string, *>}
71
     */
72
    this.fmt = {
73
      /** @type {string} */
74
      chunkId: '',
75
      /** @type {number} */
76
      chunkSize: 0,
77
      /** @type {number} */
78
      audioFormat: 0,
79
      /** @type {number} */
80
      numChannels: 0,
81
      /** @type {number} */
82
      sampleRate: 0,
83
      /** @type {number} */
84
      byteRate: 0,
85
      /** @type {number} */
86
      blockAlign: 0,
87
      /** @type {number} */
88
      bitsPerSample: 0,
89
      /** @type {number} */
90
      cbSize: 0,
91
      /** @type {number} */
92
      validBitsPerSample: 0,
93
      /** @type {number} */
94
      dwChannelMask: 0,
95
      /**
96
       * 4 32-bit values representing a 128-bit ID
97
       * @type {!Array<number>}
98
       */
99
      subformat: []
100
    };
101
    /**
102
     * The data of the 'fact' chunk.
103
     * @type {!Object<string, *>}
104
     */
105
    this.fact = {
106
      /** @type {string} */
107
      chunkId: '',
108
      /** @type {number} */
109
      chunkSize: 0,
110
      /** @type {number} */
111
      dwSampleLength: 0
112
    };
113
    /**
114
     * The data of the 'cue ' chunk.
115
     * @type {!Object<string, *>}
116
     */
117
    this.cue = {
118
      /** @type {string} */
119
      chunkId: '',
120
      /** @type {number} */
121
      chunkSize: 0,
122
      /** @type {number} */
123
      dwCuePoints: 0,
124
      /** @type {!Array<!Object>} */
125
      points: [],
126
    };
127
    /**
128
     * The data of the 'smpl' chunk.
129
     * @type {!Object<string, *>}
130
     */
131
    this.smpl = {
132
      /** @type {string} */
133
      chunkId: '',
134
      /** @type {number} */
135
      chunkSize: 0,
136
      /** @type {number} */
137
      dwManufacturer: 0,
138
      /** @type {number} */
139
      dwProduct: 0,
140
      /** @type {number} */
141
      dwSamplePeriod: 0,
142
      /** @type {number} */
143
      dwMIDIUnityNote: 0,
144
      /** @type {number} */
145
      dwMIDIPitchFraction: 0,
146
      /** @type {number} */
147
      dwSMPTEFormat: 0,
148
      /** @type {number} */
149
      dwSMPTEOffset: 0,
150
      /** @type {number} */
151
      dwNumSampleLoops: 0,
152
      /** @type {number} */
153
      dwSamplerData: 0,
154
      /** @type {!Array<!Object>} */
155
      loops: []
156
    };
157
    /**
158
     * The data of the 'bext' chunk.
159
     * @type {!Object<string, *>}
160
     */
161
    this.bext = {
162
      /** @type {string} */
163
      chunkId: '',
164
      /** @type {number} */
165
      chunkSize: 0,
166
      /** @type {string} */
167
      description: '', //256
168
      /** @type {string} */
169
      originator: '', //32
170
      /** @type {string} */
171
      originatorReference: '', //32
172
      /** @type {string} */
173
      originationDate: '', //10
174
      /** @type {string} */
175
      originationTime: '', //8
176
      /**
177
       * 2 32-bit values, timeReference high and low
178
       * @type {!Array<number>}
179
       */
180
      timeReference: [0, 0],
181
      /** @type {number} */
182
      version: 0, //WORD
183
      /** @type {string} */
184
      UMID: '', // 64 chars
185
      /** @type {number} */
186
      loudnessValue: 0, //WORD
187
      /** @type {number} */
188
      loudnessRange: 0, //WORD
189
      /** @type {number} */
190
      maxTruePeakLevel: 0, //WORD
191
      /** @type {number} */
192
      maxMomentaryLoudness: 0, //WORD
193
      /** @type {number} */
194
      maxShortTermLoudness: 0, //WORD
195
      /** @type {string} */
196
      reserved: '', //180
197
      /** @type {string} */
198
      codingHistory: '' // string, unlimited
199
    };
200
    /**
201
     * The data of the 'ds64' chunk.
202
     * Used only with RF64 files.
203
     * @type {!Object<string, *>}
204
     */
205
    this.ds64 = {
206
      /** @type {string} */
207
      chunkId: '',
208
      /** @type {number} */
209
      chunkSize: 0,
210
      /** @type {number} */
211
      riffSizeHigh: 0, // DWORD
212
      /** @type {number} */
213
      riffSizeLow: 0, // DWORD
214
      /** @type {number} */
215
      dataSizeHigh: 0, // DWORD
216
      /** @type {number} */
217
      dataSizeLow: 0, // DWORD
218
      /** @type {number} */
219
      originationTime: 0, // DWORD
220
      /** @type {number} */
221
      sampleCountHigh: 0, // DWORD
222
      /** @type {number} */
223
      sampleCountLow: 0 // DWORD
224
      /** @type {number} */
225
      //'tableLength': 0, // DWORD
226
      /** @type {!Array<number>} */
227
      //'table': []
228
    };
229
    /**
230
     * The data of the 'data' chunk.
231
     * @type {!Object<string, *>}
232
     */
233
    this.data = {
234
      /** @type {string} */
235
      chunkId: '',
236
      /** @type {number} */
237
      chunkSize: 0,
238
      /** @type {!Uint8Array} */
239
      samples: new Uint8Array(0)
240
    };
241
    /**
242
     * The data of the 'LIST' chunks.
243
     * Each item in this list look like this:
244
     *  {
245
     *      chunkId: '',
246
     *      chunkSize: 0,
247
     *      format: '',
248
     *      subChunks: []
249
     *   }
250
     * @type {!Array<!Object>}
251
     */
252
    this.LIST = [];
253
    /**
254
     * The data of the 'junk' chunk.
255
     * @type {!Object<string, *>}
256
     */
257
    this.junk = {
258
      /** @type {string} */
259
      chunkId: '',
260
      /** @type {number} */
261
      chunkSize: 0,
262
      /** @type {!Array<number>} */
263
      chunkData: []
264
    };
265
    /**
266
     * The bit depth code according to the samples.
267
     * @type {string}
268
     */
269
    this.bitDepth = '0';
270
    /**
271
     * @type {!Object}
272
     * @protected
273
     */
274
    this.dataType = {};
275
    // Load a file from the buffer if one was passed
276
    // when creating the object
277
    if (wavBuffer) {
278
      this.fromBuffer(wavBuffer);
279
    }
280
  }
281
282
  /**
283
   * Set up the WaveFileParser object from a byte buffer.
284
   * @param {!Uint8Array} wavBuffer The buffer.
285
   * @param {boolean=} samples True if the samples should be loaded.
286
   * @throws {Error} If container is not RIFF, RIFX or RF64.
287
   * @throws {Error} If format is not WAVE.
288
   * @throws {Error} If no 'fmt ' chunk is found.
289
   * @throws {Error} If no 'data' chunk is found.
290
   */
291
  fromBuffer(wavBuffer, samples=true) {
292
    this.clearHeader();
293
    this.head_ = 0;
294
    this.readRIFFChunk(wavBuffer);
295
    if (this.format != 'WAVE') {
296
      throw Error('Could not find the "WAVE" format identifier');
297
    }
298
    this.setSignature(wavBuffer);
299
    this.readDs64Chunk_(wavBuffer);
300
    this.readFmtChunk_(wavBuffer);
301
    this.readFactChunk_(wavBuffer);
302
    this.readBextChunk_(wavBuffer);
303
    this.readCueChunk_(wavBuffer);
304
    this.readSmplChunk_(wavBuffer);
305
    this.readDataChunk_(wavBuffer, samples);
306
    this.readJunkChunk_(wavBuffer);
307
    this.readLISTChunk_(wavBuffer);
308
    this.bitDepthFromFmt_();
309
    this.updateDataType();
310
  }
311
312
  /**
313
   * Reset some attributes of the object.
314
   * @protected
315
   */
316
  clearHeader() {
317
    this.fmt.cbSize = 0;
318
    this.fmt.validBitsPerSample = 0;
319
    this.fact.chunkId = '';
320
    this.ds64.chunkId = '';
321
  }
322
323
  /**
324
   * Update the type definition used to read and write the samples.
325
   * @protected
326
   */
327
  updateDataType() {
328
    this.dataType = {
329
      bits: ((parseInt(this.bitDepth, 10) - 1) | 7) + 1,
330
      fp: this.bitDepth == '32f' || this.bitDepth == '64',
331
      signed: this.bitDepth != '8',
332
      be: this.container == 'RIFX'
333
    };
334
    if (['4', '8a', '8m'].indexOf(this.bitDepth) > -1 ) {
335
      this.dataType.bits = 8;
336
      this.dataType.signed = false;
337
    }
338
  }
339
340
  /**
341
   * Set the string code of the bit depth based on the 'fmt ' chunk.
342
   * @private
343
   */
344
  bitDepthFromFmt_() {
345
    if (this.fmt.audioFormat === 3 && this.fmt.bitsPerSample === 32) {
346
      this.bitDepth = '32f';
347
    } else if (this.fmt.audioFormat === 6) {
348
      this.bitDepth = '8a';
349
    } else if (this.fmt.audioFormat === 7) {
350
      this.bitDepth = '8m';
351
    } else {
352
      this.bitDepth = this.fmt.bitsPerSample.toString();
353
    }
354
  }
355
356
  /**
357
   * Read the 'fmt ' chunk of a wave file.
358
   * @param {!Uint8Array} buffer The wav file buffer.
359
   * @throws {Error} If no 'fmt ' chunk is found.
360
   * @private
361
   */
362
  readFmtChunk_(buffer) {
363
    /** @type {?Object} */
364
    let chunk = this.findChunk('fmt ');
365
    if (chunk) {
366
      this.head_ = chunk.chunkData.start;
367
      this.fmt.chunkId = chunk.chunkId;
368
      this.fmt.chunkSize = chunk.chunkSize;
369
      this.fmt.audioFormat = this.readNumber(buffer, this.uInt16_);
370
      this.fmt.numChannels = this.readNumber(buffer, this.uInt16_);
371
      this.fmt.sampleRate = this.readNumber(buffer, this.uInt32_);
372
      this.fmt.byteRate = this.readNumber(buffer, this.uInt32_);
373
      this.fmt.blockAlign = this.readNumber(buffer, this.uInt16_);
374
      this.fmt.bitsPerSample = this.readNumber(buffer, this.uInt16_);
375
      this.readFmtExtension_(buffer);
376
    } else {
377
      throw Error('Could not find the "fmt " chunk');
378
    }
379
  }
380
381
  /**
382
   * Read the 'fmt ' chunk extension.
383
   * @param {!Uint8Array} buffer The wav file buffer.
384
   * @private
385
   */
386
  readFmtExtension_(buffer) {
387
    if (this.fmt.chunkSize > 16) {
388
      this.fmt.cbSize = this.readNumber(buffer, this.uInt16_);
389
      if (this.fmt.chunkSize > 18) {
390
        this.fmt.validBitsPerSample = this.readNumber(buffer, this.uInt16_);
391
        if (this.fmt.chunkSize > 20) {
392
          this.fmt.dwChannelMask = this.readNumber(buffer, this.uInt32_);
393
          this.fmt.subformat = [
394
            this.readNumber(buffer, this.uInt32_),
395
            this.readNumber(buffer, this.uInt32_),
396
            this.readNumber(buffer, this.uInt32_),
397
            this.readNumber(buffer, this.uInt32_)];
398
        }
399
      }
400
    }
401
  }
402
403
  /**
404
   * Read the 'fact' chunk of a wav file.
405
   * @param {!Uint8Array} buffer The wav file buffer.
406
   * @private
407
   */
408
  readFactChunk_(buffer) {
409
    /** @type {?Object} */
410
    let chunk = this.findChunk('fact');
411
    if (chunk) {
412
      this.head_ = chunk.chunkData.start;
413
      this.fact.chunkId = chunk.chunkId;
414
      this.fact.chunkSize = chunk.chunkSize;
415
      this.fact.dwSampleLength = this.readNumber(buffer, this.uInt32_);
416
    }
417
  }
418
419
  /**
420
   * Read the 'cue ' chunk of a wave file.
421
   * @param {!Uint8Array} buffer The wav file buffer.
422
   * @private
423
   */
424
  readCueChunk_(buffer) {
425
    /** @type {?Object} */
426
    let chunk = this.findChunk('cue ');
427
    if (chunk) {
428
      this.head_ = chunk.chunkData.start;
429
      this.cue.chunkId = chunk.chunkId;
430
      this.cue.chunkSize = chunk.chunkSize;
431
      this.cue.dwCuePoints = this.readNumber(buffer, this.uInt32_);
432
      for (let i = 0; i < this.cue.dwCuePoints; i++) {
433
        this.cue.points.push({
434
          dwName: this.readNumber(buffer, this.uInt32_),
435
          dwPosition: this.readNumber(buffer, this.uInt32_),
436
          fccChunk: this.readString(buffer, 4),
437
          dwChunkStart: this.readNumber(buffer, this.uInt32_),
438
          dwBlockStart: this.readNumber(buffer, this.uInt32_),
439
          dwSampleOffset: this.readNumber(buffer, this.uInt32_),
440
        });
441
      }
442
    }
443
  }
444
445
  /**
446
   * Read the 'smpl' chunk of a wave file.
447
   * @param {!Uint8Array} buffer The wav file buffer.
448
   * @private
449
   */
450
  readSmplChunk_(buffer) {
451
    /** @type {?Object} */
452
    let chunk = this.findChunk('smpl');
453
    if (chunk) {
454
      this.head_ = chunk.chunkData.start;
455
      this.smpl.chunkId = chunk.chunkId;
456
      this.smpl.chunkSize = chunk.chunkSize;
457
      this.smpl.dwManufacturer = this.readNumber(buffer, this.uInt32_);
458
      this.smpl.dwProduct = this.readNumber(buffer, this.uInt32_);
459
      this.smpl.dwSamplePeriod = this.readNumber(buffer, this.uInt32_);
460
      this.smpl.dwMIDIUnityNote = this.readNumber(buffer, this.uInt32_);
461
      this.smpl.dwMIDIPitchFraction = this.readNumber(buffer, this.uInt32_);
462
      this.smpl.dwSMPTEFormat = this.readNumber(buffer, this.uInt32_);
463
      this.smpl.dwSMPTEOffset = this.readNumber(buffer, this.uInt32_);
464
      this.smpl.dwNumSampleLoops = this.readNumber(buffer, this.uInt32_);
465
      this.smpl.dwSamplerData = this.readNumber(buffer, this.uInt32_);
466
      for (let i = 0; i < this.smpl.dwNumSampleLoops; i++) {
467
        this.smpl.loops.push({
468
          dwName: this.readNumber(buffer, this.uInt32_),
469
          dwType: this.readNumber(buffer, this.uInt32_),
470
          dwStart: this.readNumber(buffer, this.uInt32_),
471
          dwEnd: this.readNumber(buffer, this.uInt32_),
472
          dwFraction: this.readNumber(buffer, this.uInt32_),
473
          dwPlayCount: this.readNumber(buffer, this.uInt32_),
474
        });
475
      }
476
    }
477
  }
478
479
  /**
480
   * Read the 'data' chunk of a wave file.
481
   * @param {!Uint8Array} buffer The wav file buffer.
482
   * @param {boolean} samples True if the samples should be loaded.
483
   * @throws {Error} If no 'data' chunk is found.
484
   * @private
485
   */
486
  readDataChunk_(buffer, samples) {
487
    /** @type {?Object} */
488
    let chunk = this.findChunk('data');
489
    if (chunk) {
490
      this.data.chunkId = 'data';
491
      this.data.chunkSize = chunk.chunkSize;
492
      if (samples) {
493
        this.data.samples = buffer.slice(
494
          chunk.chunkData.start,
495
          chunk.chunkData.end);
496
      }
497
    } else {
498
      throw Error('Could not find the "data" chunk');
499
    }
500
  }
501
502
  /**
503
   * Read the 'bext' chunk of a wav file.
504
   * @param {!Uint8Array} buffer The wav file buffer.
505
   * @private
506
   */
507
  readBextChunk_(buffer) {
508
    /** @type {?Object} */
509
    let chunk = this.findChunk('bext');
510
    if (chunk) {
511
      this.head_ = chunk.chunkData.start;
512
      this.bext.chunkId = chunk.chunkId;
513
      this.bext.chunkSize = chunk.chunkSize;
514
      this.bext.description = this.readString(buffer, 256);
515
      this.bext.originator = this.readString(buffer, 32);
516
      this.bext.originatorReference = this.readString(buffer, 32);
517
      this.bext.originationDate = this.readString(buffer, 10);
518
      this.bext.originationTime = this.readString(buffer, 8);
519
      this.bext.timeReference = [
520
        this.readNumber(buffer, this.uInt32_),
521
        this.readNumber(buffer, this.uInt32_)];
522
      this.bext.version = this.readNumber(buffer, this.uInt16_);
523
      this.bext.UMID = this.readString(buffer, 64);
524
      this.bext.loudnessValue = this.readNumber(buffer, this.uInt16_);
525
      this.bext.loudnessRange = this.readNumber(buffer, this.uInt16_);
526
      this.bext.maxTruePeakLevel = this.readNumber(buffer, this.uInt16_);
527
      this.bext.maxMomentaryLoudness = this.readNumber(buffer, this.uInt16_);
528
      this.bext.maxShortTermLoudness = this.readNumber(buffer, this.uInt16_);
529
      this.bext.reserved = this.readString(buffer, 180);
530
      this.bext.codingHistory = this.readString(
531
        buffer, this.bext.chunkSize - 602);
532
    }
533
  }
534
535
  /**
536
   * Read the 'ds64' chunk of a wave file.
537
   * @param {!Uint8Array} buffer The wav file buffer.
538
   * @throws {Error} If no 'ds64' chunk is found and the file is RF64.
539
   * @private
540
   */
541
  readDs64Chunk_(buffer) {
542
    /** @type {?Object} */
543
    let chunk = this.findChunk('ds64');
544
    if (chunk) {
545
      this.head_ = chunk.chunkData.start;
546
      this.ds64.chunkId = chunk.chunkId;
547
      this.ds64.chunkSize = chunk.chunkSize;
548
      this.ds64.riffSizeHigh = this.readNumber(buffer, this.uInt32_);
549
      this.ds64.riffSizeLow = this.readNumber(buffer, this.uInt32_);
550
      this.ds64.dataSizeHigh = this.readNumber(buffer, this.uInt32_);
551
      this.ds64.dataSizeLow = this.readNumber(buffer, this.uInt32_);
552
      this.ds64.originationTime = this.readNumber(buffer, this.uInt32_);
553
      this.ds64.sampleCountHigh = this.readNumber(buffer, this.uInt32_);
554
      this.ds64.sampleCountLow = this.readNumber(buffer, this.uInt32_);
555
      //if (wav.ds64.chunkSize > 28) {
556
      //  wav.ds64.tableLength = unpack(
557
      //    chunkData.slice(28, 32), uInt32_);
558
      //  wav.ds64.table = chunkData.slice(
559
      //     32, 32 + wav.ds64.tableLength);
560
      //}
561
    } else {
562
      if (this.container == 'RF64') {
563
        throw Error('Could not find the "ds64" chunk');
564
      }
565
    }
566
  }
567
568
  /**
569
   * Read the 'LIST' chunks of a wave file.
570
   * @param {!Uint8Array} buffer The wav file buffer.
571
   * @private
572
   */
573
  readLISTChunk_(buffer) {
574
    /** @type {?Object} */
575
    let listChunks = this.findChunk('LIST', true);
576
    if (listChunks !== null) {
577
      for (let j=0; j < listChunks.length; j++) {
578
        /** @type {!Object} */
579
        let subChunk = listChunks[j];
580
        this.LIST.push({
581
          chunkId: subChunk.chunkId,
582
          chunkSize: subChunk.chunkSize,
583
          format: subChunk.format,
584
          subChunks: []});
585
        for (let x=0; x<subChunk.subChunks.length; x++) {
586
          this.readLISTSubChunks_(subChunk.subChunks[x],
587
            subChunk.format, buffer);
588
        }
589
      }
590
    }
591
  }
592
593
  /**
594
   * Read the sub chunks of a 'LIST' chunk.
595
   * @param {!Object} subChunk The 'LIST' subchunks.
596
   * @param {string} format The 'LIST' format, 'adtl' or 'INFO'.
597
   * @param {!Uint8Array} buffer The wav file buffer.
598
   * @private
599
   */
600
  readLISTSubChunks_(subChunk, format, buffer) {
601
    if (format == 'adtl') {
602
      if (['labl', 'note','ltxt'].indexOf(subChunk.chunkId) > -1) {
603
        this.head_ = subChunk.chunkData.start;
604
        /** @type {!Object<string, string|number>} */
605
        let item = {
606
          chunkId: subChunk.chunkId,
607
          chunkSize: subChunk.chunkSize,
608
          dwName: this.readNumber(buffer, this.uInt32_)
609
        };
610
        if (subChunk.chunkId == 'ltxt') {
611
          item.dwSampleLength = this.readNumber(buffer, this.uInt32_);
612
          item.dwPurposeID = this.readNumber(buffer, this.uInt32_);
613
          item.dwCountry = this.readNumber(buffer, this.uInt16_);
614
          item.dwLanguage = this.readNumber(buffer, this.uInt16_);
615
          item.dwDialect = this.readNumber(buffer, this.uInt16_);
616
          item.dwCodePage = this.readNumber(buffer, this.uInt16_);
617
        }
618
        item.value = this.readZSTR(buffer, this.head_);
619
        this.LIST[this.LIST.length - 1].subChunks.push(item);
620
      }
621
    // RIFF INFO tags like ICRD, ISFT, ICMT
622
    } else if(format == 'INFO') {
623
      this.head_ = subChunk.chunkData.start;
624
      this.LIST[this.LIST.length - 1].subChunks.push({
625
        chunkId: subChunk.chunkId,
626
        chunkSize: subChunk.chunkSize,
627
        value: this.readZSTR(buffer, this.head_)
628
      });
629
    }
630
  }
631
632
  /**
633
   * Read the 'junk' chunk of a wave file.
634
   * @param {!Uint8Array} buffer The wav file buffer.
635
   * @private
636
   */
637
  readJunkChunk_(buffer) {
638
    /** @type {?Object} */
639
    let chunk = this.findChunk('junk');
640
    if (chunk) {
641
      this.junk = {
642
        chunkId: chunk.chunkId,
643
        chunkSize: chunk.chunkSize,
644
        chunkData: [].slice.call(buffer.slice(
645
          chunk.chunkData.start,
646
          chunk.chunkData.end))
647
      };
648
    }
649
  }
650
}
651